/*

*/

#define _CRT_SECURE_NO_DEPRECATE

#include "od.h"
#include "AppUI.h"
#include "PluginCfg.h"

#pragma comment(lib, "ollydbg.lib")

HINSTANCE hinst;
HWND      hwmain;

t_status  g_LastState = STAT_NONE;

typedef struct
{
	ulong  index;
	ulong  size;
	ulong  type;
	DWORD  address;
}t_handler;


#define IS_CONTAINED(p1,s1,p2,s2)( ( (LPBYTE)(p1) >= (p2) ) && \
								   ( (LPBYTE)(p1) +  (s1) ) <= ( (LPBYTE) (p2) + (s2) ) )


void calcSelRVA(void* item, int origin);
///////////////////////////////////////

BOOL WINAPI DllEntryPoint(HINSTANCE hi,DWORD reason,LPVOID reserved) 
{
	if (reason == DLL_PROCESS_ATTACH)
	{
		hinst = hi;
		DoHook();
	}
	return 1;                            
};

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		hinst = hModule;
		DoHook();
		break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}


extc int _export cdecl ODBG_Plugindata(char shortname[32]) 
{
	strcpy(shortname, PLUGIN_NAME);
	return PLUGIN_VERSION;
}

extc int _export cdecl ODBG_Plugininit(int OdbgVersion, HWND hw, ulong *features) 
{
	if ( OdbgVersion < PLUGIN_VERSION )
		return -1;

	hwmain = hw;

	Addtolist(0, 0, "OdEx plugin v0.2");
    Addtolist(0, -1, "  Written by Snow (Q:85703533)");

	g_UIEngine.Init_UI(hinst, hwmain);

	return 0;
}

extc int _export cdecl ODBG_Pluginmenu(int origin, char *data, void *item) 
{
	int retval = 0;

	switch (origin) 
	{
	case PM_MAIN:
		strcpy(data, "0 Setting,1 Show InfoWnd|2 About");
		return 1;	
		
	case PM_DISASM:
		strcpy(data, "0 &ShowInfo");
		return 1;
		
	case PM_CPUDUMP:
		return 0;

	case PM_CPUSTACK:
		return 0;
	}
	
	return 0;
}

extc void _export cdecl ODBG_Pluginaction(int origin, int action, void *item) 
{
	switch (origin) 
	{
	case PM_MAIN:
		switch (action) 
		{
		case 0:
			g_UIEngine.ShowSettingDlg();
			break;
		case 1:
			g_UIEngine.ShowInfoDlg();
			break;
		case 2:
			MessageBoxA(hwmain, "OdEx PlugIn v0.2\nwritten by Snow (Q:85703533) 2018", "About", MB_ICONASTERISK);
			break;
		}
		break;	
		
	case PM_DISASM:
		switch (action) 
		{
		case 0:
			calcSelRVA(item, origin);
			break;
		}
		break;
		
	case PM_CPUDUMP:
		switch (action) 
		{
		case 0:
			calcSelRVA(item, origin);
			break;
		}
		break;

	case PM_CPUSTACK:
		switch (action) 
		{
		case 0:
			calcSelRVA(item, origin);
			break;
		}
		break;
	}
}


extc int _export cdecl ODBG_Pluginclose(void) 
{	
	// Unregister both plugin classes and destroy all data (sorted and allocated) 

	return 0;
}

void SetTopWindow(HWND hWnd)
{
// 	HWND hForeWnd = GetForegroundWindow();
// 	DWORD dwForeID = GetWindowThreadProcessId(hForeWnd, NULL);
// 	DWORD dwCurID = GetCurrentThreadId();
//	AttachThreadInput(dwCurID, dwForeID, TRUE);
	if (IsIconic(hWnd))
		ShowWindow(hWnd, SW_RESTORE);
// 	SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
// 	SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
// 	SetForegroundWindow(hWnd);
//	AttachThreadInput(dwCurID, dwForeID, FALSE);
}

// This function is called each time OllyDbg passes main Windows loop. When
// debugged application stops, b ring command line window in foreground.
extc void _export cdecl ODBG_Pluginmainloop(DEBUG_EVENT *debugevent)
{
	t_status status;
	status = Getstatus();

	if (status != g_LastState)
	{
		g_LastState = status;

		if (status == STAT_STOPPED)
		{
			FLASHWINFO _flashInfo;
			_flashInfo.cbSize = sizeof(FLASHWINFO);
			_flashInfo.hwnd = hwmain;
			_flashInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
			_flashInfo.dwTimeout = 0;
			_flashInfo.uCount = _UI32_MAX;
			FlashWindowEx(&_flashInfo);
			if (g_Config.bShowMemInfo)
			{
				SetTopWindow(hwmain);
			}
		}
	}
}

void calcSelRVA(void* item, int origin)
{
    t_dump* pd;
    t_memory* pmem;
    t_disasm da;
	t_module* pmodule;
	UINT64 sel_addr;
    char data[16] = "";

    pd = (t_dump *)item;
	if (origin == PM_CPUDUMP || origin == PM_CPUSTACK) {
		Readmemory(data, pd->sel0, 8, MM_RESILENT);
		sel_addr = *(DWORD*)data;
	}else 
		sel_addr = pd->sel0;

	g_UIEngine.UpdateInfo(sel_addr);
}
